package com.pai4j.user.service;
import cn.dev33.satoken.stp.StpUtil;
import com.alibaba.nacos.common.utils.CollectionUtils;
import com.pai4j.common.constants.WebConstant;
import com.pai4j.common.enums.RoleCodeEnum;
import com.pai4j.common.enums.UserStatusEnum;
import com.pai4j.common.exception.BusinessException;
import com.pai4j.common.util.*;
import cn.dev33.satoken.stp.SaTokenInfo;
import com.pai4j.common.enums.RedisKeyEnum;
import com.pai4j.common.enums.messagequeue.MessageQueueEnum;
import com.pai4j.common.service.messagequeue.producer.MessageQueueProducer;
import com.pai4j.domain.dto.BindWxRequestDTO;
import com.pai4j.domain.dto.UpdatePasswordDTO;
import com.pai4j.domain.vo.request.RegisterRequestDTO;
import com.pai4j.domain.vo.request.UpdateUserInfoResquest;
import com.pai4j.domain.vo.request.request.UserRegistryInfoRequestVO;
import com.pai4j.domain.vo.response.UserBaseResponseInfoVO;
import com.pai4j.domain.vo.response.UserBaseResponseVO;
import com.pai4j.user.repository.dao.IUserDAO;
import com.pai4j.user.repository.entity.UserEntity;
import com.pai4j.user.service.relation.AccountRelationFactory;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

import static com.pai4j.common.util.NameUtil.generateRandomName;

/**
 * 用户服务处理层
 *
 * @author: CYM-pai
 * @date: 2025/04/16 20:01
 **/
@Slf4j
@Service
public class UserService {
    
    // 密码加密盐值
    private String salt = "pai4j";
    
    /***
     * USER ID 前缀
     * U: 用户ID
     * R: 机器人ID
     * G: 群组ID
     * P: 专题账号ID
     */
    private static final String USER_ID_PREFIX = "U";
    private static final String ROBOT_ID_PREFIX = "R";
    private static final String GROUP_ID_PREFIX = "G";
    private static final String SUBJECT_ACCOUNT_ID_PREFIX = "S";
    
    @Autowired
    private RedisUtil redisUtil;
    
    @Resource
    private IUserDAO userDAO;
    
    @Autowired
    private MessageQueueProducer<Object, Long> messageQueueProducer;
    
    
    public UserBaseResponseVO getUserBaseByMobile(String mobile) {
        
        UserEntity user = userDAO.findByMobile(mobile);
        if (user != null) {
            UserBaseResponseVO userBaseResponseVO = new UserBaseResponseVO();
            BeanUtils.copyProperties(user, userBaseResponseVO);
            return userBaseResponseVO;
        }
        return null;
    }
    
    /**
     * 用户注册 - 注册成功自动登录
     * 这里其实不需要事务，因为想分享事务管理器的用法和场景，刻意添加了事务注解
     * 为了后续将统一登录和微信公众号扫码登录接口统一，
     * 后面这里的uid要和手机号绑定存入redis,然后将uid传入sotoken框架进行登录操作
     * @return
     */
    
    @Transactional
    public boolean registry(UserRegistryInfoRequestVO request) {
        // 参数校验
        String userName = request.getUserName();
        String mobile = request.getMobile();
        this.validateRegistryParam(userName, mobile);
        // 注册信息入库
        String uid = this.registryUser2DB(request);
        // 建立 mobile -> uid 的长期关联缓存
        try {
            String mobileKey = RedisKeyEnum.LOGIN_CODE_CACHE.getKey(mobile);
            redisUtil.set(mobileKey, uid, RedisKeyEnum.LOGIN_CODE_CACHE.getExpireTime());
        } catch (Exception e) {
            log.warn("cache mobile->uid mapping failed, mobile={}, uid={}", mobile, uid, e);
        }
        // 注册成功，事务结束后刷新用户缓存信息
        TransactionSyncManagerUtil.registerSynchronization(() -> {
            // 刷新用户缓存
            this.refreshAndGetUserEntityFromCache(uid);
            // 同步账号信息至搜索
            try {
                UserEntity entity = userDAO.findByUid(uid);
                UserBaseResponseInfoVO vo = convertBaseVo(entity);
                if (vo != null) {
                    messageQueueProducer.send(MessageQueueEnum.QUEUE_ACCOUNT_SYNC_ES, vo);
                }
            } catch (Exception e) {
                log.warn("publish account sync message failed, uid={}", uid, e);
            }
        });
        return true;
    }
    
    
    private void validateRegistryParam(String userName, String mobile) {
        if (hasUserInfo(mobile)) {
            throw new BusinessException("用户已存在");
        }
        if (!Pattern.matches("^[0-9a-zA-Z_]{1,}$", mobile)) {
            throw new BusinessException("账号格式不合法");
        }
        if (StringUtils.isBlank(userName) || userName.length() < 2 || userName.length() > 12) {
            throw new BusinessException("用户名不合法：2~12位字符");
        }
        if (userNameIsExist(userName)) {
            throw new BusinessException("用户名已经被占用，换一个吧");
        }
    }
    
    /**
     * 判断用户是否存在
     *
     * @param mobile
     * @return
     */
    private boolean hasUserInfo(String mobile) {
        return userDAO.findByMobile(mobile) != null;
    }
    
    private boolean userNameIsExist(String userName) {
        
        return userDAO.findByUserName(userName) != null;
    }
    
    /**
     * 注册用户到数据库: 手机号加密码的注册
     * @ registerRequestDTO 注册信息
     */
    private String registryUser2DB(UserRegistryInfoRequestVO registerRequestDTO) {
        UserEntity userEntity = new UserEntity();
        String uid = IDGenerateUtil.createId(USER_ID_PREFIX);
        userEntity.setUid(uid);
        userEntity.setPaiId(uid);
        userEntity.setUserId(uid);
        userEntity.setIsWx(0);
        userEntity.setUserName(StringUtil.handleSpecialHtmlTag(registerRequestDTO.getUserName()));
        userEntity.setPhoto(registerRequestDTO.getPhoto());
        userEntity.setMobile(registerRequestDTO.getMobile());
        userEntity.setStatus(UserStatusEnum.ENABLE.getStatus());
        userEntity.setPassword(md5Pwd(registerRequestDTO.getPassword()));
        userEntity.setRoleCode(RoleCodeEnum.USER.getCode());
        userEntity.setCreateBy(uid);
        userEntity.setPaiCoin(10);
        userEntity.setSignature("暂无签名~");
        // 注册用户
        return userDAO.save(userEntity).getUid();
    }
    
    /**
     * 用户登录服务实现方法
     * sa-token 通过以下步骤生成并解析 loginId：
     * 在用户登录时，调用 StpUtil.login(userId) 将 userId 存储到 token 中。
     * 在后续请求中，客户端携带该 token。
     * 服务器通过解析 token 提取出 loginId
     *
     * @param validCode 登录验证码
     * @return saTokenInfo 登录结果
     */
    @Transactional
    public SaTokenInfo doLogin(String validCode) {
        // 优先按扫码登录验证码(validCode)处理
        String loginKey = RedisKeyEnum.LOGIN_CODE_CACHE.getKey(validCode);
        String openId = redisUtil.get(loginKey);
        if (StringUtils.isNotBlank(openId)) {
            //先判断用户是否已经绑定微信公众号
            UserEntity userEntity = userDAO.findByUid(openId);
            if(userEntity == null){
                UserEntity userEntity1 = userDAO.findByUserId(openId);
                if(userEntity1 == null){
                    // uid和userId都没有说明这个用户是新用户
                    UserRegistryInfoRequestVO registerRequestDTO = new UserRegistryInfoRequestVO();
                    this.registryUser2DB(registerRequestDTO);
                }
                String userId = userEntity1.getUserId();
                // 使用 openId 登录
                StpUtil.login(userId);
                SaTokenInfo saTokenInfo = StpUtil.getTokenInfo();
                // 建立 TOKEN -> openId 映射
                String satoken = saTokenInfo.getTokenValue();
                String openIdKey = RedisKeyEnum.OPENID_LOGINID_CACHE.getKey(satoken);
                redisUtil.set(openIdKey, userId, RedisKeyEnum.OPENID_LOGINID_CACHE.getExpireTime());
                return saTokenInfo;
            }
            String userId = userEntity.getUserId();
            // 使用 openId 登录
            StpUtil.login(userId);
            SaTokenInfo saTokenInfo = StpUtil.getTokenInfo();
            // 建立 TOKEN -> openId 映射
            String satoken = saTokenInfo.getTokenValue();
            String openIdKey = RedisKeyEnum.OPENID_LOGINID_CACHE.getKey(satoken);
            redisUtil.set(openIdKey, userId, RedisKeyEnum.OPENID_LOGINID_CACHE.getExpireTime());
            return saTokenInfo;
        }
        return null;
    }
    
    
    /**
     * 根据satoken获取openId
     *
     * @author: CYM-pai
     * @date: 2025/04/24 10:35
     **/
    public String getopenIdBysatoken(String satoken) {
        String openIdKey = RedisKeyEnum.OPENID_LOGINID_CACHE.getKey(satoken);
        String openId = redisUtil.get(openIdKey);
        return openId;
    }
    
    /**
     *    微信扫码关注公众号时的用户自动注册
     *
     * @author: CYM-pai
     * @date: 2025/04/17 10:35
     **/
    @Transactional
    public Boolean register(RegisterRequestDTO request) {
        
        if (StringUtils.isBlank(request.getUserId())) {
            return false;
        }
        RegisterRequestDTO registerRequestDTO = new RegisterRequestDTO();
        registerRequestDTO.setUserId(request.getUserId());
        String userName = generateRandomName();
        String photo = AvatarUtil.getRandomAvatar();
        String password = md5Pwd(WebConstant.WX_LOGIN_PASSWORD);
        String uid = IDGenerateUtil.createId(USER_ID_PREFIX);
        registerRequestDTO.setUserName(userName);
        registerRequestDTO.setPassword(password);
        registerRequestDTO.setPhoto(photo);
        registerRequestDTO.setUid(uid);
        registerRequestDTO.setMobile(null);
        registerRequestDTO.setPaiCoin(WebConstant.DEFAULT_PI_COIN_NUMBER);
        //注册信息入库:uids = userId = openId
        String uids = registerUser2DB(registerRequestDTO);
        TransactionSyncManagerUtil.registerSynchronization(() -> {
            // 刷新用户缓存
            this.refreshAndGetUserEntityFromCache(uids);
            // 同步账号信息至搜索
            try {
                UserEntity entity = userDAO.findByUserId(uids);
                UserBaseResponseInfoVO vo = convertBaseVo(entity);
                if (vo != null) {
                    messageQueueProducer.send(MessageQueueEnum.QUEUE_ACCOUNT_SYNC_ES, vo);
                }
            } catch (Exception e) {
                log.warn("publish account sync message failed, userId={}", uids, e);
            }
        });
        return true;
    }
    
    /**
     * 刷新并获取用户实体信息
     * 此方法首先尝试从缓存中获取用户信息如果信息已缓存且不需要刷新，则直接返回缓存信息
     * 否则，将从数据库中查询最新信息，并更新缓存
     *
     * @param userId       用户ID，用于查询用户信息
     * @param refreshCache 可变参数，指示是否需要刷新缓存如果传入，则表示需要刷新
     * @return 返回用户实体信息，如果未找到则返回null
     */
    private UserEntity refreshAndGetUserEntityFromCache(String userId, boolean... refreshCache) {
        // 构造Redis缓存的键
        String key = RedisKeyEnum.USER_INFO_CACHE.getKey(userId);
        // 从Redis中获取缓存的用户信息
        String val = redisUtil.get(key);
        // 判断是否需要刷新缓存
        boolean refresh = refreshCache != null && refreshCache.length > 0 && refreshCache[0];
        // 如果不需要刷新缓存且缓存值存在，则直接返回缓存的用户信息
        if (!refresh && StringUtils.isNotBlank(val)) {
            return JsonUtil.fromJson(val, UserEntity.class);
        }
        // 从数据库中查询用户信息
        UserEntity userEntity = userDAO.findByUserId(userId);
        // 如果查询到用户信息，则更新缓存
        if (userEntity != null) {
            this.refreshUserDetailCache(userEntity);
        }
        // 返回查询到的用户信息
        return userEntity;
    }
    
    /**
     * 刷新用户详情redis缓存
     *
     * @param userEntity
     */
    private void refreshUserDetailCache(UserEntity userEntity) {
        if (userEntity == null) {
            return;
        }
        String key = RedisKeyEnum.USER_INFO_CACHE.getKey(userEntity.getUserId());
        redisUtil.set(key, JsonUtil.toJsonString(userEntity), RedisKeyEnum.USER_INFO_CACHE.getExpireTime());
    }
    
    /**
     * 注册用户信息存储入库
     *
     * @author: CYM-pai
     * @date: 2025/04/17 10:35
     **/
    private String registerUser2DB(RegisterRequestDTO registerRequestDTO) {
        UserEntity userEntity = new UserEntity();
        userEntity.setUid(registerRequestDTO.getUid());
        userEntity.setUserId(registerRequestDTO.getUserId());
        userEntity.setIsWx(1);
        userEntity.setPaiId(registerRequestDTO.getUid());
        userEntity.setUserName(registerRequestDTO.getUserName());
        userEntity.setPassword(md5Pwd(registerRequestDTO.getPassword()));
        userEntity.setPhoto(registerRequestDTO.getPhoto());
        userEntity.setPaiCoin(registerRequestDTO.getPaiCoin());
        userEntity.setMobile(registerRequestDTO.getMobile());
        userEntity.setRoleCode(RoleCodeEnum.USER.getCode());
        userEntity.setStatus(UserStatusEnum.ENABLE.getStatus());
        userEntity.setCreateBy(registerRequestDTO.getUserId());
        userEntity.setSignature("暂无签名~");
        userEntity.setCreateDate(new Date());
        //注册用户
        return userDAO.save(userEntity).getUserId();
    }
    
    /**
     * md5加密密码
     *
     * @author: CYM-pai
     * @date: 2025/04/17 10:35
     **/
    private String md5Pwd(String password) {
        return MD5Utils.md5(password.concat(WebConstant.MD5_SALT));
    }
    
    /**
     * 根据用户ID获取用户信息
     *
     * @author: CYM-pai
     * @date: 2025/04/23 09:32
     **/
    public UserBaseResponseInfoVO getUserInfoByUserId(String userId) {
        
        return getUserBaseInfoByUserId(userId);
    }
    
    public UserBaseResponseInfoVO getUserBaseInfoByUserId(String userId) {
        if (StringUtils.isBlank(userId)) {
            return null;
        }
        return getUserBaseInfoByUserIdFromCache(userId);
    }
    
    /**
     * 从缓存中获取用户基本信息
     *
     * @author: CYM-pai
     * @date: 2025/04/23 09:38
     **/
    private UserBaseResponseInfoVO getUserBaseInfoByUserIdFromCache(String userId) {
        if (userId == null) {
            return null;
        }
        UserEntity entity = this.refreshAndGetUserEntityFromCache(userId, true);
        UserBaseResponseInfoVO userBaseResponseInfoVO = convertBaseVo(entity);
        if (userBaseResponseInfoVO == null) {
            return null;
        }
        return userBaseResponseInfoVO;
    }

    /**
     * 从缓存中获取用户信息（公共方法，对外提供）
     * 别名方法，用于兼容性调用
     *
     * @param account 用户账号/用户ID
     * @return 用户基本信息
     */
    public UserBaseResponseInfoVO getUserInfoFromCache(String account) {
        return getUserBaseInfoByUserIdFromCache(account);
    }
    
    /**
     * 将用户实体转换为基本信息VO
     *
     * @author: CYM-pai
     * @date: 2025/04/23 09:38
     **/
    public static UserBaseResponseInfoVO convertBaseVo(UserEntity entity) {
        if (entity == null) {
            return null;
        }
        UserBaseResponseInfoVO vo = new UserBaseResponseInfoVO();
        BeanUtils.copyProperties(entity, vo);
        return vo;
    }
    
    /**
     * 修改用户基本信息
     *
     * @author: CYM-pai
     * @date: 2025/04/25 21:31
     **/
    public boolean updateUserBaseInfo(UpdateUserInfoResquest updateRequest) {
        if (updateRequest == null) {
            return false;
        }
        String userId = updateRequest.getUserId();
        String uid = updateRequest.getUid();
        if (StringUtils.isNotEmpty(userId)) {
            //1、先从缓存中获取用户信息 、若缓存在不存在，则从数据库中获取，并插入缓存中
            UserEntity userEntity = this.refreshAndGetUserEntityFromCache(userId, true);
            userEntity.setUserName(updateRequest.getUserName());
            userEntity.setPhoto(updateRequest.getPhoto());
            userEntity.setSignature(updateRequest.getSignature());
            userEntity.setMobile(updateRequest.getMobile());
            userEntity.setUpdateBy(updateRequest.getUserId());
            userEntity.setUpdateDate(new Date());
            //先更新缓存，再更新数据库
            this.refreshUserDetailCache(userEntity);
            userDAO.save(userEntity);
            // 发送账号同步消息
            try {
                UserBaseResponseInfoVO vo = convertBaseVo(userEntity);
                if (vo != null) {
                    messageQueueProducer.send(MessageQueueEnum.QUEUE_ACCOUNT_SYNC_ES, vo);
                }
            } catch (Exception e) {
                log.warn("publish account sync message failed, userId={}", userId, e);
            }
            return true;
        }else {
            UserEntity userEntity = userDAO.findByUid(uid);
            userEntity.setUserName(updateRequest.getUserName());
            userEntity.setPhoto(updateRequest.getPhoto());
            userEntity.setSignature(updateRequest.getSignature());
            userEntity.setMobile(updateRequest.getMobile());
            userEntity.setUpdateBy(updateRequest.getUid());
            userEntity.setUpdateDate(new Date());
            userDAO.save(userEntity);
            // 发送账号同步消息
            try {
                UserBaseResponseInfoVO vo = convertBaseVo(userEntity);
                if (vo != null) {
                    messageQueueProducer.send(MessageQueueEnum.QUEUE_ACCOUNT_SYNC_ES, vo);
                }
            } catch (Exception e) {
                log.warn("publish account sync message failed, uid={}", uid, e);
            }
            return true;
        }
    }
    
    
    /**
     * 批量走redis查询用户详情
     *
     * @param userIds
     * @return
     */
    public Map<String, UserBaseResponseInfoVO> batchGet(Set<String> userIds) {
        
        return this.batchGetUserInfoFromCache(new ArrayList<>(userIds));
    }
    
    
    /**
     * 批量查询用户缓存
     * <p>
     * 本函数通过Redis批量获取用户信息缓存，如果缓存中不存在，则通过用户ID查询用户基本信息
     * 主要目的是为了提高用户信息查询的效率，减少数据库的访问压力
     *
     * @param userIdList 用户ID列表，用于查询用户信息
     * @return 返回一个映射，键为用户ID，值为用户基本信息对象UserBaseResponseInfoVO
     */
    public Map<String, UserBaseResponseInfoVO> batchGetUserInfoFromCache(List<String> userIdList) {
        // 初始化用户信息映射
        Map<String, UserBaseResponseInfoVO> userBaseResponseInfoVOMap = new HashMap<>();
        // 检查用户ID列表是否为空，如果为空则直接返回空映射
        if (CollectionUtils.isEmpty(userIdList)) {
            return userBaseResponseInfoVOMap;
        }
        // 构造缓存键列表，对应用户ID列表中的每个用户ID
        List<String> cacheKeys = userIdList.stream().map(k ->
                RedisKeyEnum.USER_INFO_CACHE.getKey(String.valueOf(k))).collect(Collectors.toList());
        // 批量从Redis中获取缓存信息，并解析为映射
        Map<String, String> multiResultMap = redisUtil.mgetAndParseMap(cacheKeys);
        // 遍历用户ID列表，获取用户信息
        for (int i = 0; i < userIdList.size(); i++) {
            String userId = userIdList.get(i);
            String cacheKey = cacheKeys.get(i);
            String cache = multiResultMap.get(cacheKey);
            UserBaseResponseInfoVO userBaseResponseInfoVO;
            // 如果缓存信息不为空，则解析缓存信息为用户基本信息对象
            if (StringUtils.isNotBlank(cache)) {
                //解析缓存信息cache为UserBaseResponseInfoVO对象
                userBaseResponseInfoVO = JsonUtil.fromJson(cache, UserBaseResponseInfoVO.class);
            } else {
                // 如果缓存信息为空，则通过用户ID查询用户基本信息
                userBaseResponseInfoVO = getUserBaseInfoByUserId(userId);
            }
            // 将用户ID和对应的用户基本信息对象存入映射
            userBaseResponseInfoVOMap.put(userId, userBaseResponseInfoVO);
        }
        // 返回用户信息映射
        return userBaseResponseInfoVOMap;
    }
    
    /**
     * 批量从缓存中获取用户列表信息
     * 此方法重载了另一个方法，允许接受Set类型参数
     * 主要用于简化调用过程，不需要调用方关心Set到List的转换
     *
     * @param userIdSet 用户ID集合
     * @return 用户信息列表
     */
    public List<UserBaseResponseInfoVO> batchGetUserListInfoFromCache(Set<String> userIdSet) {
        // 将Set转换为List，调用另一个重载方法进行处理
        return this.batchGetUserListInfoFromCache(new ArrayList<>(userIdSet));
    }
    
    /**
     * 批量从缓存中获取用户列表信息
     * 接受一个用户ID列表，从缓存中获取每个用户的信息如果缓存中没有找到信息，则调用另一个方法获取信息
     *
     * @param userIdList 用户ID列表
     * @return 用户信息列表
     */
    public List<UserBaseResponseInfoVO> batchGetUserListInfoFromCache(List<String> userIdList) {
        // 检查输入列表是否为空，如果为空，直接返回空列表
        if (CollectionUtils.isEmpty(userIdList)) {
            return Collections.emptyList();
        }
        
        // 根据用户ID列表生成缓存键列表
        List<String> cacheKeys = userIdList.stream().map(k ->
                RedisKeyEnum.USER_INFO_CACHE.getKey(String.valueOf(k))).collect(Collectors.toList());
        
        // 批量从缓存中获取信息，并解析为Map类型
        Map<String, String> multiResultMap = redisUtil.mgetAndParseMap(cacheKeys);
        
        // 初始化用户信息列表
        List<UserBaseResponseInfoVO> userBaseResponseInfoVOList = new ArrayList<>();
        
        // 遍历用户ID列表和缓存键列表，获取用户信息
        for (int i = 0; i < userIdList.size(); i++) {
            String userId = userIdList.get(i);
            String cacheKey = cacheKeys.get(i);
            String cache = multiResultMap.get(cacheKey);
            
            UserBaseResponseInfoVO userBaseResponseInfoVO;
            // 如果缓存不为空，则解析缓存为用户信息对象
            if (StringUtils.isNotBlank(cache)) {
                userBaseResponseInfoVO = JsonUtil.fromJson(cache, UserBaseResponseInfoVO.class);
            } else {
                // 如果缓存为空，则根据用户ID获取信息
                userBaseResponseInfoVO = getUserBaseInfoByUserId(userId);
            }
            
            // 如果用户信息对象不为空，则添加到用户信息列表中
            if (userBaseResponseInfoVO != null) {
                userBaseResponseInfoVOList.add(userBaseResponseInfoVO);
            }
        }
        
        // 返回用户信息列表
        return userBaseResponseInfoVOList;
    }
    
    
    /**
     * 查询指定订阅用户
     *
     * @param relationType 关系类型
     * @param account
     * @return
     */
    public Set<String> getAllSubscriberByAccount(Integer relationType, String account) {
        
        return AccountRelationFactory.getServiceByType(relationType).getAllSubscriber(account);
    }
    
    /**
     * 判断userAccount是否订阅account
     *
     * @param relationType
     * @param userAccount
     * @param account
     * @return
     */
    public Boolean isSubscribe(Integer relationType, String userAccount, String account) {
        
        return AccountRelationFactory.getServiceByType(relationType).isSubscribe(userAccount, account);
    }
    
    
    /**
     * 创建群组到数据库
     *
     * @param groupName
     * @param createUserId
     */
    public String registerGroup2DB(String groupName, String groupPhoto, String createUserId) {
        UserEntity userEntity = new UserEntity();
        String groupId = IDGenerateUtil.createId(GROUP_ID_PREFIX);
        userEntity.setUserId(groupId);
        userEntity.setPaiId(groupId);
        userEntity.setUid(groupId);
        userEntity.setUserName(StringUtil.handleSpecialHtmlTag(groupName));
        userEntity.setPhoto(groupPhoto);
        userEntity.setMobile("-");
        userEntity.setStatus(UserStatusEnum.ENABLE.getStatus());
        // 密码设置为用户ID, 本身也不支持登录
        userEntity.setPassword(md5Pwd(groupId));
        userEntity.setRoleCode(RoleCodeEnum.GROUP.getCode());
        userEntity.setCreateBy(createUserId);
        // 创建群组
        userDAO.save(userEntity);
        // 注册成功，事务结束后刷新群组缓存
        TransactionSyncManagerUtil.registerSynchronization(() ->
                this.refreshAndGetUserEntityFromCache(groupId));
        return groupId;
    }
    
    /**
     * 根据用户名查询用户信息
     *
     * @author: CYM-pai
     * @date: 2025/06/27 14:31
     **/
    public UserBaseResponseVO getUserBaseInfoByUserName(String name) {
        UserEntity user = userDAO.findByUserName(name);
        if (user != null) {
            UserBaseResponseVO userBaseResponseVO = new UserBaseResponseVO();
            BeanUtils.copyProperties(user, userBaseResponseVO);
            return userBaseResponseVO;
        }
        return null;
    }
    
    public UserBaseResponseInfoVO getUserInfoByUid(String uid) {
        if (StringUtils.isNotBlank(uid)) {
            UserEntity user = userDAO.findByUid(uid);
            UserBaseResponseInfoVO userBaseResponseInfoVO = new UserBaseResponseInfoVO();
            BeanUtils.copyProperties(user, userBaseResponseInfoVO);
            return userBaseResponseInfoVO;
        }
        return null;
    }
    
    public Boolean updateUserBaseInfoByUid(BindWxRequestDTO request) {
        String key = RedisKeyEnum.LOGIN_CODE_CACHE.getKey(request.getValidCode());
        String openId = redisUtil.get(key);
        UserEntity userEntity = userDAO.findByUid(request.getUid());
        userEntity.setUserId(openId);
        userEntity.setIsWx(1);
        userEntity.setUpdateDate(new Date());
        userDAO.save(userEntity);
        return true;
    }
    
    public boolean updatePassword(UpdatePasswordDTO request) {
        UserEntity user = userDAO.findByUid(request.getUid());
        if (user == null) {
            return false;
        }
        if (!user.getPassword().equals(md5Pwd(request.getOldPassword()))) {
            return false;
        }
        user.setPassword(md5Pwd(request.getNewPassword()));
        user.setUpdateDate(new Date());
        userDAO.save(user);
        return true;
      }


      /**
       * 获取用户注册时间
       *
       * @param userId
       * @return
       */
    public String getRegisterTime(String userId) {
        return userDAO.findByUserId(userId).getCreateDate().toString();
    }

    /**
     * 混合搜索用户信息 - 支持用户名、手机号、uid三种方式搜索
     *
     * @param searchValue 搜索值（用户名/手机号/uid）
     * @return 用户基础信息
     */
    public UserBaseResponseInfoVO hybridSearch(String searchValue) {
        if (StringUtils.isBlank(searchValue)) {
            return null;
        }
        
        UserEntity userEntity = null;
        
        // 1. 首先尝试按uid搜索
        if (searchValue.startsWith("U") || searchValue.startsWith("R") || searchValue.startsWith("G") || searchValue.startsWith("S") || searchValue.startsWith("A")) {
            userEntity = userDAO.findByUid(searchValue);
        }
        // 2. 如果uid搜索没有结果，尝试按paiId搜索
        if (userEntity == null) {
            userEntity = userDAO.findByPaiId(searchValue);
        }
        // 2. 如果uid搜索没有结果，尝试按用户名搜索
        if (userEntity == null) {
            userEntity = userDAO.findByUserName(searchValue);
        }
        
        // 3. 如果用户名搜索没有结果，尝试按手机号搜索
        if (userEntity == null) {
            userEntity = userDAO.findByMobile(searchValue);
        }
        
        // 转换为响应VO
        if (userEntity != null) {
            UserBaseResponseInfoVO userBaseResponseInfoVO = new UserBaseResponseInfoVO();
            BeanUtils.copyProperties(userEntity, userBaseResponseInfoVO);
            return userBaseResponseInfoVO;
        }
        
        return null;
    }
}
